我們的短期目標是,在網頁上用純文字的方式直接顯示遊戲狀態
並會隨著遊戲更新的時候更新
原本想要把 遊戲 存在房間裡面,但是在這邊已經不需要其他房間的功能了,多一層很煩
我就直接在 ETS 再開另一個表格 叫 games 然後用跟房間一樣的 id 來儲存遊戲狀態
在 lib/card/application.ex 裡面加在之前的 rooms 表格後面
# 建立 rooms 與 games table 給大家用
:ets.new(:rooms, [:set, :public, :named_table])
:ets.new(:games, [:set, :public, :named_table])
開始寫這一頁的 mount 方法吧
要做的事情有
我們先把發牌員做好
新開一個檔案/lib/card/dealer.ex
defmodule Card.Dealer do
  use GenServer
  def init(_) do
    {:ok, []}
  end
  def handle_call(id, _from, games) do
    case :ets.lookup(:games, id) do
      [{^id, pid}] -> {:reply, {id, pid}, games}
      [] ->
        {:ok, pid} = Card.Game.start()
        :ets.insert(:games, {id, pid})
        {:reply, {id, pid}, [id | games]}
    end
  end
  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: :dealer)
  end
  def maybe_create_game(id) do
    GenServer.call(:dealer, id)
  end
end
每次開始一個新的遊戲,雙方都會想要得到遊戲的 pid
所以統一由一個發牌員來建立,來避免雙方同時各自建立分開的遊戲的情況
再將發牌員放到 lib/card/application.ex 的 start 方法的 children 裡面
  def start(_type, _args) do
    children = [
      # Start the Telemetry supervisor
      CardWeb.Telemetry,
      # Start the PubSub system
      {Phoenix.PubSub, name: Card.PubSub},
      # Start the Endpoint (http/https)
      CardWeb.Endpoint,
      # Start a worker by calling: Card.Worker.start_link(arg)
      # {Card.Worker, arg}
      Card.Dealer # 加在這裡
    ]
    # 建立 rooms 與 games table 給大家用
    :ets.new(:rooms, [:set, :public, :named_table])
    :ets.new(:games, [:set, :public, :named_table])
    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Card.Supervisor]
    Supervisor.start_link(children, opts)
  end
ok 之後就回來做 mount 方法
defmodule CardWeb.GameLive.Game do
  use CardWeb, :live_view
  import CardWeb.Component
  alias Card.Game
  def mount(%{"id" => id} = _params, _session, socket) do
    # 請 dealer 給我們一個遊戲
    pid = Card.Dealer.find_or_create_game(id)
    # 用拿到的 pid 跟 查看遊戲狀態
    game = Game.status(pid)
    
    # 把這些資訊存進 assigns 裡面
    {:ok, assign(socket, %{pid: pid, id: id, game: game})}
  end
  # 接著就可以在 畫面上 用 inspect 方法 把原始的資料型態印在網頁上
  def render(assigns) do
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <.logo />
      <%= inspect @game %>
    </div>
    """
  end
end
建立遊戲後,畫面上會有遊戲剛開始的狀態
如果重新整理,可以看到會依照自動出牌的進度,遊戲狀態有改變
但是我們不可能邊玩邊重新整理
明天來用 pubsub 自動更新遊戲狀態